#pragma once
#include <vector>
#include <queue>
#include <iostream>
#include <memory>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Log.hpp"
#include <unistd.h>
#include <functional>
#include "Cond.hpp"

namespace ThreadPoolModule
{
    using namespace ThreadModule;
    using namespace LockModule;
    using namespace LogModule;
    using namespace CondModule;
    using thread_t = std::shared_ptr<Thread>;
    const int defaultnum = 5; // 默认的线程个数
    template <class T>
    class ThreadPool
    {
    private:
        int _num;
        std::queue<T> _Taskq;           // 任务队列
        std::vector<thread_t> _threads; // 维护线程的数组
        bool _isrunning;                // 线程池的状态
        Mutex _mutex;
        Cond _cond;
        int _wait_num; // 在条件变量中等待的线程个数
        void DefaultFunc()
        {
            int cnt = 5;
            while (cnt--)
            {
                LOG(LogLevel::INFO) << "hello world";
                sleep(1);
            }
        }
        bool IsEmpty() { return _Taskq.empty(); }
        void HandlerRequest(const std::string &s)
        {
            LOG(LogLevel::INFO) << "线程: [" << s << "] 进行HandlerRequest等待处理";
            // 我们要让线程不断的从任务队列获取任务去执行。
            while (true)
            {
                T t;
                {
                    LockGuard lock(_mutex);
                    // 队列为空 && 线程池还在运行才可以进行等待
                    while (IsEmpty() && _isrunning)
                    {
                        _wait_num++;
                        _cond.Wait(_mutex);
                        _wait_num--;
                    }

                    // 3. 线程不为空 && 不在运行 ，那么此时就可以直接退出循环了
                    if (IsEmpty() && !_isrunning)
                        break;
                    // 剩余两种情况：
                    //  队列不为空 && 线程停止了，这时候要让线程尽快吧所有任务处理完毕
                    //  队列不为空 && 线程正在运行，正常处理任务
                    t = _Taskq.front();
                    _Taskq.pop();
                }
                // 执行任务不需要加锁，线程执行自己的!!!
                t(s); // 未来规定，你必须给我传递可以使用()直接调用的方法
            }
        }
        ThreadPool(int num = defaultnum)
            : _num(num), _isrunning(false)
        {
            for (int i = 0; i < _num; i++)
            {
                _threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerRequest, this, std::placeholders::_1)));
                LOG(LogLevel::INFO) << "创建线程: [" << _threads.back()->Name() << "]成功";
            }
        }
        ThreadPool(const ThreadPool<T>&) = delete;
        ThreadPool(const ThreadPool<T>&&) = delete;
        ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;
        ThreadPool<T>& operator=(const ThreadPool<T>&&) = delete;

        static ThreadPool<T> *_instance;
        static Mutex mutex; // 单独一个锁来对单例进行加锁
    public:
        static ThreadPool<T> *Getinstance()
        {
            LOG(LogLevel::INFO) << "获取线程池单例";
            if (_instance == nullptr)
            {
                LockGuard lock(mutex);
                if (_instance == nullptr)
                {
                    _instance = new ThreadPool<T>();
                }
            }
            return _instance;
        }

        void Start()
        {
            LockGuard lock(_mutex);
            if (_isrunning)
                return;        // 防止重复启动
            _isrunning = true; // 这个_isrunning不能放在循环后面 ?? TODO
            for (auto &thread_ptr : _threads)
            {
                thread_ptr->Start();
                LOG(LogLevel::INFO) << "线程: [" << thread_ptr->Name() << "] 启动成功";
            }
        }
        void Equeue(T &&in)
        {
            LockGuard lock(_mutex);
            // 线程池必须处于运行状态
            if (!_isrunning)
            {
                LOG(LogLevel::ERROR) << "线程池未启动";
                return;
            }
            _Taskq.push(std::move(in));
            if (_wait_num) // 如果此时有线程在等待，唤醒它。
                _cond.Notify();
        }

        void Stop()
        {
            LockGuard lock(_mutex);
            // 线程池必须处于运行状态
            if (!_isrunning)
                return;
            // 3. 不能在入任务
            _isrunning = false;
            // 1. 让线程自己退出(唤醒) && 2. 历史的任务被处理完毕
            if (_wait_num)
            {
                LOG(LogLevel::INFO) << "唤醒所有线程，让他们尽快处理完毕";
                _cond.NotifyAll(); // 唤醒所有等待的线程，让他们把任务处理完毕
            }
        }

        // 进程池是否运行都可以直接wait。
        void Wait()
        {
            LOG(LogLevel::INFO) << "开始回收线程： ";
            for (auto &thread_ptr : _threads)
            {
                thread_ptr->Join();
                LOG(LogLevel::INFO) << "线程: [" << thread_ptr->Name() << "] 退出成功";
            }
        }
        ~ThreadPool() {}
    };
    template <class T>
    ThreadPool<T> *ThreadPool<T>::_instance = nullptr;
    template <class T>
    Mutex ThreadPool<T>::mutex; // 单独一个锁来对单例进行加锁
}